package service

import (
	"errors"
	"fmt"
	"cgs-server/helper"
	"cgs-server/server"
	"cgs-server/server/model"
	"cgs-server/server/store"
	"go.mongodb.org/mongo-driver/bson"
	"mime/multipart"
	"strings"
)

type BimSrv interface {
	UploadFile (file *multipart.FileHeader, user *model.User) error
	TranslateFile (bimTranslateModel *model.BimTranslateModel, user *model.User) error
	UpdateFile (mdl *model.BimModel, user *model.User) error
	DeleteFile (fileId string, user *model.User) error
	GetSupportType() (*model.BimResult, error)
	ListFile(user *model.User) ([]*model.BimModel, error)
	ViewToken(fileId string) (*model.BimResult, error)
	FileInfo(fileId string) (*model.BimModel, error)
}

type bimSrv struct {
	// store
	store store.Factory
}

func (b *bimSrv) FileInfo(fileId string) (*model.BimModel, error) {
	bimModel, err := b.store.Bim().Get(&model.BimModel{FileId: fileId}, nil)
	return bimModel, err
}

func (b *bimSrv) ViewToken(fileId string) (*model.BimResult, error) {
	bimResult, err := GetViewToken(fileId)
	if err != nil {
		return nil, err
	}
	if bimResult.NotSuccess() {
		return nil, fmt.Errorf("request view token error: %s", bimResult.Message)
	}

	return bimResult, nil
}

func (b *bimSrv) ListFile(user *model.User) ([]*model.BimModel, error) {
	return b.store.Bim().List(&model.BimModel{}, user)
}

func (b *bimSrv) GetSupportType() (*model.BimResult, error) {
	bimResult, err := SupportTypes()
	if err != nil {
		return nil, err
	}
	if bimResult.NotSuccess() {
		return nil, errors.New("get bim support types failed")
	}

	return bimResult, err
}

func (b *bimSrv) DeleteFile(fileId string, user *model.User) error {

	// 先查询一下
	bimModel, err := b.store.Bim().Get(&model.BimModel{FileId: fileId}, user)
	if err != nil {
		return err
	}

	// 调用 bimface 接口删除
	result, err := DeleteFile(fileId)
	if err != nil {
		return err
	}
	if result.NotSuccess() {
		return errors.New(result.Message)
	}

	// 更新数据库
	err = b.store.Bim().Delete(bimModel, user)
	return err
}

func (b *bimSrv) UpdateFile(mdl *model.BimModel, user *model.User) error {
	err := b.store.Bim().Update(mdl, user)
	if err != nil {
		return err
	}
	// 将文件转换状态推给前端
	sendBimTranslateStatus(mdl)

	return nil
}

func (b *bimSrv) TranslateFile(bimTranslateModel *model.BimTranslateModel, user *model.User) error {

	// 1. 根据 fileId 查询当前文件，检查转换状态
	bimModel, err := b.store.Bim().Get(&model.BimModel{FileId: bimTranslateModel.Source.FileId}, user)
	if err != nil {
		return err
	}
	if bimModel.IsStatusSuccess() || bimModel.IsStatusProcessing() {
		return nil // 已经转换成功 或者正在转换
	}

	// 2. 调用 bimface 发起转换
	data := bson.M{}
	toJSON, _ := helper.ToJSON(bimTranslateModel)
	_ = helper.FromJSON(toJSON, &data)
	bimResult, err := TranslateFile(data)
	if err != nil {
		return err
	}
	if bimResult.NotSuccess() {
		return errors.New(bimResult.Message)
	}

	data, ok := bimResult.Data.(map[string]interface{})
	if !ok {
		return errors.New("translate result data is empty")
	}

	status := data["status"].(string)
	bimModel.TranslateStatus = status

	if status == "processing" {
		err = b.UpdateFile(bimModel, user)
		return err
	} else if status == "failed" {
		err = b.UpdateFile(bimModel, user)
		return errors.New(data["reason"].(string))
	}

	// 转换成功，更新数据库 thumbnail
	thumbnail := data["thumbnail"].([]interface{})
	thumb := make([]string, 0, len(thumbnail))
	for _, t := range thumbnail {
		thumb = append(thumb, t.(string))
	}
	bimModel.Thumbnail = thumb

	databagId := data["databagId"].(string)
	bimModel.DatabagId = databagId

	err = b.UpdateFile(bimModel, user)
	return err
}

func newBimSrv(s *service) BimSrv {
	return &bimSrv{store: s.store}
}

func (b *bimSrv) UploadFile(file *multipart.FileHeader, user *model.User) error {

	// 1.调用 bimface 接口，保存文件
	uploadFile, err := UploadFile(file)
	if err != nil {
		return err
	}

	if uploadFile.NotSuccess() || uploadFile.Data == nil {
		return errors.New(uploadFile.Message)
	}

	data, ok := uploadFile.Data.(map[string]interface{})
	if !ok {
		return errors.New("policy data is empty")
	}

	// 2.保存到数据库

	fileName := data["name"].(string)
	suffix := data["suffix"].(string)
	name := strings.TrimSuffix(fileName, "."+suffix)

	fileType := file.Header.Get("Content-Type")

	bimModel := &model.BimModel{
		Name: name,
		FileName: fileName,
		Type: suffix,
		FileType: fileType,
		FileSize: file.Size,
		FileId: data["fileId"].(string),
	}

	err = b.store.Bim().Save(bimModel, user)

	return err
}

func sendBimTranslateStatus(bimModel *model.BimModel) {
	//log.Println("send ", bimModel.FileId, bimModel.TranslateStatus)
	server.WebsocketHub.Send(&server.BroadcastMessage{
		Type: "bim_translate_status",
		Data: bson.M{
			"fileId": bimModel.FileId,
			"status": bimModel.TranslateStatus,
		},
	})
}